#ifndef _NE_TERRAIN_H_
#define _NE_TERRAIN_H_

#include <common/Object.h>
#include <mathematics/Vector3.h>
#include <graphics/Viewport.h>
#include <graphics/Texture.h>

namespace ne
{
    struct TerrainTriangle
    {
        uint32_t mFace[3];
        real mMinHeight;
        real mMaxHeight;
        TerrainTriangle *mpParent;
        TerrainTriangle *mpLeftChild;
        TerrainTriangle *mpRightChild;
        TerrainTriangle *mpLeftNeighbor;
        TerrainTriangle *mpRightNeighbor;
        TerrainTriangle *mpBottomNeighbor;
        bool mSplit;
    };

    // vertex enabled = δ* threshold < max(|dx|, |dy|, |dy|)

    class NEAPI Terrain : public Object
    {
        public:
            explicit Terrain(const std::string &name);

            void generateTerrainData(Image *pHeightData);

            void update(const Viewport *pViewport);

            const std::vector<Vector4>& getVertexList() const;

            const std::vector<Vector3>& getNormalList() const;

            const std::vector<Color>& getColorList() const;

            const std::vector<uint32_t>& getIndexList() const;

            real getHeightAt(const Vector2 &v) const;

            real getHeightAt(const Vector3 &v) const;

            real getHeightAt(const real x, const real y) const;

            void destroyTerrainData();

            ~Terrain();

        private:
            Terrain();

            Terrain(const Terrain &);

            Terrain& operator = (const Terrain &);

            real _getHeightFromColor(const Color &c) const;

            void _generateNormalAndColorAt(const uint32_t x, const uint32_t y);

            bool _needSplitTriangle(TerrainTriangle *pTriangle) const;

            void _splitTerrain(TerrainTriangle *pTriangle);

            void _splitTriangle(TerrainTriangle *pTriangle);

            void _updateTerrain(TerrainTriangle *pTriangle, const bool bForce=false);

            void _updateTriangle(TerrainTriangle *pTriangle);

            void _destroyTriangle(TerrainTriangle *pTriangle);

        private:
            TerrainTriangle *mpTriangle;
            uint32_t mWidth;
            uint32_t mHeight;
            Image *mpHeightData;
            std::vector<Vector4> mVertexList;
            std::vector<Vector3> mNormalList;
            std::vector<Color> mColorList;
            std::vector<uint32_t> mIndexList;
            std::deque<TerrainTriangle*> mSplitTriangleDeque;
            std::map<TerrainTriangle*, bool> mUpdateTriangleMap;

            Vector3 mCameraPos;
    };
}

#endif
